package org.linlinjava.litemall.wx.config;

import com.alibaba.fastjson.JSON;
import org.linlinjava.litemall.db.domain.LitemallMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Set;

@ServerEndpoint("/wx/message/ws/{userId}")
@Component
public class WebSocketServer {
    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);

    // 静态初始化块，用于调试
    static {
        System.out.println("🔌 WebSocketServer类正在被加载...");
        System.out.println("📍 WebSocket端点路径: /wx/message/ws/{userId}");
    }

    /**
     * 存储用户WebSocket连接 Map<用户ID, WebSocket会话>
     */
    private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 用来存放每个客户端对应的 WebSocketServer 对象
     */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 当前连接用户ID
     */
    private String userId;

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
//        logger.info("🎯 收到WebSocket连接请求 - userId: {}, sessionId: {}", userId, session.getId());
//        logger.info("📍 连接URI: {}", session.getRequestURI());
//        logger.info("🔧 Session参数: {}", session.getRequestParameterMap());
//
        this.session = session;
        this.userId = userId;
        
        // 设置用户连接信息
        session.getUserProperties().put("connectTime", new java.util.Date());
        session.getUserProperties().put("lastActivity", new java.util.Date());
        session.getUserProperties().put("userId", userId);
        
        // 加入 map 中
        webSocketMap.put(userId, this);
        sessionMap.put(userId, session);
//        logger.info("✅ 用户{}建立WebSocket连接成功，当前在线用户数：{}", userId, sessionMap.size());
        
        // 发送连接成功消息
        try {
            session.getBasicRemote().sendText("连接成功！用户ID: " + userId + "，在线用户数: " + sessionMap.size());
        } catch (IOException e) {
            logger.error("发送连接成功消息失败", e);
        }
        
        // 通知其他用户有新用户上线（可选）
        notifyUserOnline(userId);
    }

    @OnClose
    public void onClose() {
        webSocketMap.remove(this.userId);
        sessionMap.remove(this.userId);
//        logger.info("❌ 用户{}断开WebSocket连接，当前在线用户数：{}", this.userId, sessionMap.size());
        
        // 通知其他用户有用户下线
        if (this.userId != null) {
            notifyUserOffline(this.userId);
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
//        logger.info("📨 收到用户{}的消息：{}", this.userId, message);
        // 回显消息测试
        try {
            session.getBasicRemote().sendText("服务器收到消息: " + message);
        } catch (IOException e) {
            logger.error("回复消息失败", e);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        logger.error("🚨 WebSocket发生错误 - userId: {}, sessionId: {}", this.userId, session.getId(), error);
        logger.error("错误类型: {}", error.getClass().getSimpleName());
        logger.error("错误消息: {}", error.getMessage());
    }

    /**
     * 发送消息给指定用户
     */
    public static void sendInfo(LitemallMessage message) {
        try {
            WebSocketServer webSocketServer = webSocketMap.get(message.getReceiverId());
            if (webSocketServer != null && webSocketServer.session.isOpen()) {
                // 接收者在线，发送消息
                String messageJson = JSON.toJSONString(message);
                sendMessage(message.getReceiverId(), messageJson);
//                logger.info("消息已推送给用户 {}", message.getReceiverId());
            } else {
                logger.info("用户{}不在线，消息将在其上线后推送", message.getReceiverId());
            }
        } catch (Exception e) {
            logger.error("发送消息失败", e);
        }
    }

    /**
     * 发送消息给指定用户
     * @return true:发送成功 false:用户不在线
     */
    public static boolean sendMessage(String userId, String message) {
        Session session = sessionMap.get(userId);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
                logger.info("WebSocket消息发送成功，接收用户：{}，消息内容：{}", userId, message);
                return true;
            } catch (IOException e) {
                logger.error("WebSocket发送消息给用户{}失败：{}", userId, e.getMessage());
                return false;
            }
        } else {
            logger.info("用户{}不在线，消息将在其上线后推送", userId);
            return false;
        }
    }

    /**
     * 发送消息（实例方法）
     */
    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 获取当前在线用户数
     */
    public static int getOnlineCount() {
        return sessionMap.size();
    }

    /**
     * 判断用户是否在线
     */
    public static boolean isOnline(Integer userId) {
        Session session = sessionMap.get(userId);
        return session != null && session.isOpen();
    }

    /**
     * 获取所有在线用户ID列表
     */
    public static Set<String> getOnlineUserIds() {
        return new HashSet<>(sessionMap.keySet());
    }

    /**
     * 获取在线用户详细信息
     */
    public static List<Map<String, Object>> getOnlineUsers() {
        List<Map<String, Object>> onlineUsers = new ArrayList<>();
        
        for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
            String userId = entry.getKey();
            Session session = entry.getValue();
            
            if (session.isOpen()) {
                Map<String, Object> userInfo = new HashMap<>();
                userInfo.put("userId", userId);
                userInfo.put("sessionId", session.getId());
                userInfo.put("connectTime", session.getUserProperties().get("connectTime"));
                userInfo.put("isOpen", session.isOpen());
                onlineUsers.add(userInfo);
            }
        }
        
        return onlineUsers;
    }

    /**
     * 向所有在线用户广播消息
     */
    public static void broadcastMessage(String message) {
        logger.info("📢 向所有在线用户广播消息: {}", message);
        
        for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
            String userId = entry.getKey();
            Session session = entry.getValue();
            
            if (session.isOpen()) {
                try {
                    session.getBasicRemote().sendText(message);
                    logger.info("✅ 广播消息发送给用户: {}", userId);
                } catch (IOException e) {
                    logger.error("❌ 广播消息发送给用户{}失败: {}", userId, e.getMessage());
                }
            }
        }
    }

    /**
     * 向指定用户列表发送消息（群聊功能）
     */
    public static void sendMessageToUsers(List<Integer> userIds, String message) {
        logger.info("📤 向指定用户组发送消息: 用户数={}, 消息={}", userIds.size(), message);
        
        for (Integer userId : userIds) {
            sendMessage(userId.toString(), message);
        }
    }

    /**
     * 获取用户的连接信息
     */
    public static Map<String, Object> getUserConnectionInfo(Integer userId) {
        Session session = sessionMap.get(userId);
        Map<String, Object> info = new HashMap<>();
        
        if (session != null) {
            info.put("userId", userId);
            info.put("isOnline", session.isOpen());
            info.put("sessionId", session.getId());
            info.put("connectTime", session.getUserProperties().get("connectTime"));
            info.put("lastActivity", session.getUserProperties().get("lastActivity"));
        } else {
            info.put("userId", userId);
            info.put("isOnline", false);
        }
        
        return info;
    }

    /**
     * 通知其他用户有新用户上线
     */
    private static void notifyUserOnline(String userId) {
        Map<String, Object> onlineData = new HashMap<>();
        onlineData.put("type", "user_online");
        onlineData.put("userId", userId);
        onlineData.put("timestamp", new java.util.Date());
        onlineData.put("onlineCount", sessionMap.size());
        
        String onlineMessage = JSON.toJSONString(onlineData);
        
        // 向所有其他在线用户发送上线通知
        for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
            String targetUserId = entry.getKey();
            Session session = entry.getValue();
            
            // 不向自己发送上线通知
            if (!targetUserId.equals(userId) && session.isOpen()) {
                try {
                    session.getBasicRemote().sendText(onlineMessage);
                } catch (IOException e) {
                    logger.error("发送用户上线通知失败: userId={}", targetUserId, e);
                }
            }
        }
    }

    /**
     * 通知其他用户有用户下线
     */
    private static void notifyUserOffline(String userId) {
        Map<String, Object> offlineData = new HashMap<>();
        offlineData.put("type", "user_offline");
        offlineData.put("userId", userId);
        offlineData.put("timestamp", new java.util.Date());
        offlineData.put("onlineCount", sessionMap.size());
        
        String offlineMessage = JSON.toJSONString(offlineData);
        
        // 向所有在线用户发送下线通知
        for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
            Session session = entry.getValue();
            if (session.isOpen()) {
                try {
                    session.getBasicRemote().sendText(offlineMessage);
                } catch (IOException e) {
                    logger.error("发送用户下线通知失败", e);
                }
            }
        }
    }

    /**
     * 更新用户最后活动时间
     */
    private void updateLastActivity() {
        if (this.session != null) {
            this.session.getUserProperties().put("lastActivity", new java.util.Date());
        }
    }
}